#include "Problem1.hpp"

using namespace Ipopt;

Problem1::Problem1(Index dimension) :
	UnconstrainedProblem(dimension) {
	assert(dimension >= 3);
}

bool Problem1::get_nlp_info(Index& n, Index& nnz_h_lag) {
	n = dimension;
	nnz_h_lag = 0;

	return true;
}

bool Problem1::get_starting_point(Index n, Number* x) {

	for (Index i = 0; i < dimension; ++i) {
		x[i] = 3;
	}

	return true;
}

bool Problem1::eval_f(Index n, const Number* x, bool new_x, Number& obj_value) {

	Number sum = 0;
	for (int i = 2; i < n; i++) {
		sum += 100 * (x[i] * x[i] + x[i - 1] * x[i - 1]) + x[i - 2] * x[i - 2];
	}
	obj_value = sum;
	return true;
}

/** Method to return the gradient of the objective */
bool Problem1::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f) {

	if (n >= 5) {
		grad_f[0] = 2 * x[0];
		grad_f[1] = 202 * x[1];

		for (int i = 2; i < n - 2; i++) {
			grad_f[i] = 402 * x[i];
		}
		grad_f[n - 2] = 400 * x[n - 2];
		grad_f[n - 1] = 200 * x[n - 1];
	} else if (n == 3) {
		grad_f[0] = 2 * x[0];
		grad_f[1] = 200 * x[1];
		grad_f[2] = 200 * x[2];
	} else { //n==4
		grad_f[0] = 2 * x[0];
		grad_f[1] = 202 * x[1];
		grad_f[2] = 400 * x[2];
		grad_f[3] = 200 * x[3];
	}

	return true;
}

void Problem1::newX(const Number* x) {
}

